package es.ucm.fdi.xtremeaudio.controlador;

import java.awt.Frame;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import javazoom.jlgui.basicplayer.BasicPlayer;
import es.ucm.fdi.xtremeaudio.modelo.beans.Bean;
import es.ucm.fdi.xtremeaudio.modelo.beans.Biblioteca;
import es.ucm.fdi.xtremeaudio.modelo.beans.Cancion;
import es.ucm.fdi.xtremeaudio.modelo.beans.Playlist;
import es.ucm.fdi.xtremeaudio.modelo.dao.Dao;
import es.ucm.fdi.xtremeaudio.modelo.dao.EstadoRepetir;
import es.ucm.fdi.xtremeaudio.modelo.fachada.Fachada;
import es.ucm.fdi.xtremeaudio.vista.AccionMenuContextual;
import es.ucm.fdi.xtremeaudio.vista.FormAyuda;
import es.ucm.fdi.xtremeaudio.vista.FormPrincipal;
import es.ucm.fdi.xtremeaudio.vista.FormTags;
import es.ucm.fdi.xtremeaudio.vista.NodoArbol;

/**
 * <ul>
 * <li><b>Proyecto:</b> XtremeAudio</li>
 * <li><b>Grupo:</b> 7 <i>(4&deg;B)</i></li>
 * <li><b>Asignatura:</b> Ingenier&iacute;a del Software</li>
 * <li><b>Curso:</b> 2010/2011</li>
 * <li><b>Centro:</b> Universidad Complutense de Madrid</li>
 * </ul>
 * 
 * El <b>Controlador</b> se encarga de conectar a la vista y al modelo de datos
 * (al cual accede a trav&eacute;s de una capa auxiliar o <i>fachada</i>), para
 * que interact&uacute;en siguiendo los conceptos asociados al patr&oacute;n MVC
 * con Fachada.
 * 
 * @author &Aacute;lvaro G&oacute;mez Porris
 * @author Elena Hern&aacute;ndez Delgado
 * @author Mar&iacute;a Trinidad Mart&iacute;n Campos
 * @author Mois&eacute;s Mart&iacute;nez Montes
 * @author Mat&iacute;as Salinero Delgado
 * 
 * @version %I%, %G%
 * 
 * @since 1.0
 * 
 * @see Dao
 * @see Fachada
 * @see FormPrincipal
 */
public class Controlador {

	/**
	 * Formulario de ayuda.
	 * 
	 * @see FormAyuda
	 */
	public static FormAyuda vistaAyuda = new FormAyuda();

	/**
	 * Formulario principal.
	 * 
	 * @see FormPrincipal
	 */
	public static FormPrincipal vistaPrincipal = new FormPrincipal();

	/**
	 * Formulario para modificar los tags de un archivo de audio.
	 * 
	 * @see FormTags
	 */
	public static FormTags vistaTags = new FormTags();

	/**
	 * Ordena a la vista que actualice los distintos componentes visuales para
	 * que muestren los datos asociados al estado actual de la biblioteca y la
	 * reproducci&oacute;n. Se ejecuta en funci&oacute;n de un temporizador
	 * asociado al bean que representa el estado general de la
	 * aplicaci&oacute;n.
	 * 
	 * @see Bean
	 * @see javax.swing.Timer
	 */
	public static void actualizaDatos() {

		/*
		 * Este método va sincronizado con el Timer del Bean
		 */
		Bean bean = Fachada.getBean();
		int tiempo = bean.getTiempoActual() + 1;
		bean.setTiempoActual(tiempo);
		actualizaProgreso(tiempo, tiempoToString(tiempo));
		Biblioteca b = bean.getBiblioteca();
		actualizaTiempo(tiempoToString(tiempo), b.getCancionSonando()
				.getStringDuracion());
		if (tiempo == bean.getBiblioteca().getCancionSonando().getDuracion()) {
			boolean aleatorio = bean.getPlayer().isAleatorio();
			if (b.getIndiceListaActual() == -1) {
				if (aleatorio
						|| (b.getIndiceCancionActual() < b.getCanciones()
								.size() - 1)
						|| ((b.getIndiceCancionActual() == b.getCanciones()
								.size() - 1) && (bean.getPlayer().getRepetir() != EstadoRepetir.R_OFF))) {
					siguiente();
				} else {
					stop();
				}
			} else if (b.getIndiceListaActual() == -2) {
				if (aleatorio
						|| (b.getIndiceBusqueda() < b.getBusqueda().size() - 1)
						|| ((b.getIndiceBusqueda() == b.getBusqueda().size() - 1) && (bean
								.getPlayer().getRepetir() != EstadoRepetir.R_OFF))) {
					siguiente();
				} else {
					stop();
				}
			} else {
				if (aleatorio
						|| (b.getPlaylistActual().getIndiceActual() < b
								.getPlaylistActual().getCanciones().size() - 1)
						|| ((b.getPlaylistActual().getIndiceActual() == b
								.getPlaylistActual().getCanciones().size() - 1) && (bean
								.getPlayer().getRepetir() != EstadoRepetir.R_OFF))) {
					siguiente();
				} else {
					stop();
				}
			}
		}
	}

	public static void actualizaTablaLista(Bean bean) {
		DefaultTableModel modelo = (DefaultTableModel) vistaPrincipal
				.getTablaLista().getModel();
		int total = modelo.getRowCount(); // Guardamos al principio, pues al
		// borrar se actualiza
		for (int i = 0; i < total; i++)
			modelo.removeRow(0); // Va borrando la primera siempre
		Biblioteca b = bean.getBiblioteca();
		boolean sonando = (b.getIndiceListaActual() == b
				.getIndiceListaSonando());
		int fila = 0;
		if (b.getIndiceListaActual() == -1) {
			Iterator<Cancion> itC = b.getCanciones().iterator();
			while (itC.hasNext()) {
				Cancion c = itC.next();
				actualizaVectorLista(modelo, sonando, fila, bean, c, b
						.getIndiceCancionActual());
				fila++;
			}
		} else if (b.getIndiceListaActual() == -2) {
			ArrayList<Integer> busqueda = b.getBusqueda();
			Iterator<Integer> itB = busqueda.iterator();
			while (itB.hasNext()) {
				int i = itB.next();
				Cancion c = b.getCanciones().get(i);
				actualizaVectorLista(modelo, sonando, fila, bean, c, b
						.getIndiceBusqueda());
				fila++;
			}
		} else {
			Playlist p = b.getPlaylistActual();
			Iterator<Integer> itP = p.getCanciones().iterator();
			while (itP.hasNext()) {
				int i = itP.next();
				Cancion c = b.getCanciones().get(i);
				actualizaVectorLista(modelo, sonando, fila, bean, c, p
						.getIndiceActual());
				fila++;
			}
		}
		vistaPrincipal.actualizaTablaLista(modelo);
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que establezca el modo
	 * de reproducci&oacute;n aleatorio y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void aleatorio() {
		Bean bean = Fachada.aleatorio();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al hacer aleatorio",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			actualizaAleatorio(bean.getPlayer().isAleatorio());
		}
	}

	/**
	 * Ordena al modelo que establezca como nueva canci&oacute;n la anterior a
	 * la que est&eacute; cargada actualmente (sonando o no) y actualiza la
	 * vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void anterior() {
		Bean bean = Fachada.anterior();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error con el boton anterior",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			actualizaReproduccion(bean);
			Biblioteca b = bean.getBiblioteca();
			int fila = 0;
			int sonando = b.getIndiceListaSonando();
			if (sonando == -1) {
				fila = b.getIndiceCancionActual();
			} else if (sonando == -2) {
				fila = b.getIndiceBusqueda();
			} else {
				fila = b.getPlaylistActual().getIndiceActual();
			}
			vistaPrincipal.actualizaSeleccion(fila + 1);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que avance la
	 * canci&oacute;n actual y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void avanzar() {
		Bean bean = Fachada.avanzar();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al avanzar", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		}
		int tiempo = bean.getTiempoActual();
		actualizaTiempo(tiempoToString(tiempo), bean.getBiblioteca()
				.getCancionSonando().getStringDuracion());
		actualizaProgreso(tiempo, tiempoToString(tiempo));
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que realice una
	 * b&uacute;squeda en la biblioteca a partir de un texto de entrada en forma
	 * de {@link String} y actualiza la vista.
	 * 
	 * @param texto
	 *            El texto a buscar
	 * 
	 * @see Biblioteca
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void buscar(String texto) {
		Bean bean = Fachada.buscar(texto);
		for (int i = 0; i < bean.getBiblioteca().getBusqueda().size(); i++) {
			System.out.println(Integer.toString(bean.getBiblioteca()
					.getBusqueda().get(i)));
		}
		actualizaTablaLista(bean);
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cambie la lista
	 * actual que se est&aacute; visualizando en la {@link #vistaPrincipal} por
	 * la indicada.
	 * <p>
	 * Si el &iacute;ndice es -1, se refiere a la biblioteca.<br/>
	 * Si es el &iacute;ndice es mayor que -1, puede referirse a una lista de la
	 * biblioteca (salvo desbordamiento).
	 * </p>
	 * Responde a un evento en el &aacute;rbol de la biblioteca mostrado en la
	 * {@link #vistaPrincipal}.
	 * 
	 * @param idLista
	 *            Identificador de la lista
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void cambiaLista(int idLista) {
		Bean bean = Fachada.cambiaLista(idLista);
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al cambiar de lista",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			actualizaTablaLista(bean);
			Biblioteca b = bean.getBiblioteca();
			if (b.getIndiceListaActual() == b.getIndiceListaSonando()) {
				vistaPrincipal
						.actualizaSeleccion(b.getIndiceCancionActual() + 1);
			} else {
				vistaPrincipal.actualizaSeleccion(1);
			}
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cambie el tiempo de
	 * reproducci&oacute;n actual y actualiza la vista.
	 * 
	 * @param segundos
	 *            El nuevo valor del tiempo de reproducción en segundos.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void cambiaTiempo(int segundos) {
		Bean bean = Fachada.cambiaTiempo(segundos);
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al cambiar el tiempo",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			int estado = bean.getPlayer().getStatus();
			if ((estado == BasicPlayer.STOPPED)
					|| (estado == BasicPlayer.OPENED)) {
				actualizaTiempo(tiempoToString(bean.getTiempoActual()), bean
						.getBiblioteca().getCancionSonando()
						.getStringDuracion());
			}
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cambie el volumen de
	 * reproducci&oacute;n actual.
	 * 
	 * @param vol
	 * 
	 * @see Dao
	 * @see Fachada
	 */
	public static void cambiaVolumen(int vol) {
		Bean bean = Fachada.cambiaVolumen(vol);
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al cambiar volumen",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cargue el archivo
	 * que contiene la biblioteca guardada en la ruta por defecto y actualiza la
	 * vista.
	 * 
	 * @see Biblioteca
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void cargarBiblioteca() {
		Bean bean = Fachada.cargarBiblioteca();
		creaArbol(bean);
		if (bean != null) {
			actualizaReproduccion(bean);
			if (bean.getBiblioteca().getIndiceCancionActual() == 0) {
				vistaPrincipal.actualizaSeleccion(1);
			}
		} else {
			JOptionPane.showMessageDialog(null,
					"Error: no se pudo cargar la biblioteca", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Oculta {@link #vistaAyuda}.
	 */
	public static void cerrarFormAyuda() {
		vistaAyuda.hide();
	}

	/**
	 * Oculta {@link #vistaTags}.
	 */
	public static void cerrarFormTags() {
		vistaTags.hide();
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cree una nueva lista
	 * de reproducci&oacute;n (vac&iacute;a) en la biblioteca y actualiza la
	 * vista.
	 * 
	 * @param padre
	 *            El {@link JFrame} padre
	 * 
	 * @see Biblioteca
	 * @see FormPrincipal
	 * @see Playlist
	 */
	public static void crearLista(JFrame padre) {
		Bean bean = Fachada.crearLista(padre);
		if (bean != null) {
			creaArbol(bean);
			actualizaReproduccion(bean);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que procese el evento
	 * generado por medio de un doble click o una pulsaci&oacute;n de la tecla
	 * <i>Enter</i> en la tabla de canciones de la {@link #vistaPrincipal} y
	 * actualiza la vista.
	 * 
	 * @param fila
	 *            La fila sobre la que se produjo el evento.
	 * @param seleccion
	 *            La fila que se marcar&aacute; como seleccionada en la tabla al
	 *            finalizar el proceso.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void dobleClickIntro(int fila, int seleccion) {
		Bean bean = Fachada.dobleClickIntro(fila);
		if (bean != null) {
			actualizaReproduccion(bean);
			vistaPrincipal.actualizaSeleccion(seleccion);
		}

	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que elimine las
	 * canciones seleccionadas de la lista actual (excepto en lista general de
	 * canciones de la biblioteca y lista de b&uacute;squeda).
	 * 
	 * @see Biblioteca
	 * @see Dao
	 * @see Fachada
	 */
	public static void eliminar() {
		Bean bean = Fachada.eliminar();
		if (bean != null) {
			actualizaTablaLista(bean);
		} else {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al eliminar", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que genere un
	 * men&uacute; contextual en el punto clicado por el rat&oacute;n con las
	 * listas actuales en la biblioteca, para procesar la adici&oacute;n de
	 * canciones a la lista asociada a cada &iacute;tem generado. Finalmente,
	 * actualiza la vista.
	 * 
	 * @param menu
	 *            El men&uacute; base al que a&ntilde;adir &iacute;tems.
	 * @param filas
	 *            Los identificadores de las canciones.
	 * @param e
	 *            El evento de rat&oacute;n que gener&oacute; la llamada.
	 * 
	 * @see AccionMenuContextual
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 * @see JMenu
	 * @see MouseEvent
	 */
	public static void generaMenuContextual(JMenu menu, int[] filas,
			MouseEvent e) {
		Bean bean = Fachada.generaMenuContextual(menu, filas);
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al generar men\00fa contextual",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			vistaPrincipal.muestraMenuContextual(e, bean.getBiblioteca()
					.getIndiceListaActual());
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cree una copia de la
	 * lista de reproducci&oacute;n actual, pudiendo elegir un nuevo nombre y
	 * actualiza la vista.
	 * 
	 * @param padre
	 *            El {@link JFrame} padre.
	 * 
	 * @see FormPrincipal
	 * @see Playlist
	 */
	public static void guardaListaComo(JFrame padre) {
		Bean bean = Fachada.guardaListaComo(padre);
		if (bean != null) {
			creaArbol(bean);
			actualizaReproduccion(bean);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s del fachada, que guarde el archivo
	 * asociado a la lista de reproducci&oacute;n (o la biblioteca completa, de
	 * ser &eacute;sta) que se est&eacute; mostrando actualmente.
	 * 
	 * @see Biblioteca
	 * @see Playlist
	 */
	public static void guardar() {
		Fachada.guardar();
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que guarde en el archivo
	 * correspondiente los nuevos valores de sus tags, obtenidos a trav&eacute;s
	 * de {@link #vistaTags} y actualiza la vista.
	 * 
	 * @see Biblioteca
	 * @see Fachada
	 * @see FormPrincipal
	 * @see FormTags
	 */
	public static void guardarTags() {
		vistaTags.hide();
		String autor = vistaTags.getFieldAutor().getText();
		String album = vistaTags.getFieldAlbum().getText();
		String titulo = vistaTags.getFieldTitulo().getText();
		String genero = vistaTags.getFieldGenero().getText();
		String anyo = vistaTags.getFieldAnyo().getText();
		String pista = vistaTags.getFieldPista().getText();
		Cancion oCancion = new Cancion(-1, autor, album, titulo, genero, anyo,
				pista, -1, "", "", "", null);
		oCancion.setPista(pista);
		Bean bean = Fachada.guardarTags(oCancion);
		if (bean != null) {
			actualizaTablaLista(bean);
			actualizaTablaInfo(bean);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que importe uno o varios
	 * archivos a la lista de canciones de la bilioteca y actualiza la vista.
	 * 
	 * @param padre
	 *            El {@link JFrame} padre.
	 * 
	 * @see Biblioteca
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void importarArchivos(JFrame padre) {
		Bean bean = Fachada.importarArchivos(padre);
		if (bean != null) {
			actualizaReproduccion(bean);
			vistaPrincipal.actualizaSeleccion(bean.getBiblioteca()
					.getIndiceCancionActual() + 1);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que importe una carpeta
	 * a la lista de canciones de la bilioteca y actualiza la vista.
	 * 
	 * @param padre
	 *            El {@link JFrame} padre.
	 * 
	 * @see Biblioteca
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void importarCarpeta(JFrame padre) {
		Bean bean = Fachada.importarCarpeta(padre);
		if (bean != null) {
			actualizaReproduccion(bean);
			vistaPrincipal.actualizaSeleccion(bean.getBiblioteca()
					.getIndiceCancionActual() + 1);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que elimine las todas
	 * las canciones de la lista actual (excepto en lista general de canciones
	 * de la biblioteca y lista de b&uacute;squeda).
	 * 
	 * @see Biblioteca
	 * @see Dao
	 * @see Fachada
	 */
	public static void limpiar() {
		Bean bean = Fachada.limpiar();
		if (bean != null) {
			actualizaTablaLista(bean);
		} else {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al limpiar", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Ordena a la vista que minimice el formulario de ayuda al usuario.
	 * 
	 * @see FormAyuda
	 * @see FormPrincipal
	 */
	public static void minimizarFormAyuda() {
		vistaAyuda.getVentana().setExtendedState(Frame.ICONIFIED);
	}

	/**
	 * 
	 * Ordena a la vista que minimice el formulario principal.
	 * 
	 * @see FormPrincipal
	 */
	public static void minimizarFormPrincipal() {
		vistaPrincipal.getVentana().setExtendedState(Frame.ICONIFIED);
	}

	/**
	 * Ordena a la vista que minimice el formulario de edici&oacute;n de tags.
	 * 
	 * @see FormPrincipal
	 * @see FormTags
	 */
	public static void minimizarFormTags() {
		vistaTags.getVentana().setExtendedState(Frame.ICONIFIED);
	}

	/**
	 * Muestra el formularo de ayuda al usuario.
	 */
	public static void muestraAyuda() {
		vistaAyuda.show();
	}

	/**
	 * Ordena a {@link #vistaTags} que se muestre, proporcion&aacute;ndole los
	 * datos iniciales adecuados asociados a sus distintos campos.
	 * 
	 * @see FormTags
	 */
	public static void muestraEdicion() {
		Cancion c = Fachada.getBean().getBiblioteca().getCancionSonando();
		vistaTags.getFieldAutor().setText(c.getAutor());
		vistaTags.getFieldAlbum().setText(c.getAlbum());
		vistaTags.getFieldTitulo().setText(c.getTitulo());
		vistaTags.getFieldGenero().setText(c.getGenero());
		vistaTags.getFieldAnyo().setText(c.getAnyo());
		vistaTags.getFieldPista().setText(c.getPista());
		vistaTags.show();
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que conmute el estado
	 * del sonido (<i>ON/OFF</i>) y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void mute() {
		Bean bean = Fachada.mute();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al hacer mute", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		} else {
			actualizaMute(bean.getPlayer().isMute());
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que ejecute la
	 * acci&oacute;n asociada con la funci&oacute;n play de la vista
	 * (<i>iniciar/continuar/pausar</i>) y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void playPausa() {
		Bean bean = Fachada.playPausa();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al reproducir", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		} else {
			String estado = bean.getEstado();
			if (estado.equals("Reproduciendo")) {
				actualizaEstado("Reproduciendo");
			} else if (estado.equals("Pausado")) {
				actualizaEstado("Pausado");
			}
			actualizaTablaLista(bean);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que cambie el modo de
	 * repetici&oacute;n.
	 * 
	 * @see Dao
	 * @see Fachada
	 */
	public static void repetir() {
		Bean bean = Fachada.repetir();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al repetir", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		} else {
			vistaPrincipal.actualizaRepetir(bean.getPlayer().getRepetir());
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que retroceda la
	 * canci&oacute;n actual y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void retroceder() {
		Bean bean = Fachada.retroceder();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al retroceder", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		}
		int tiempo = bean.getTiempoActual();
		actualizaTiempo(tiempoToString(tiempo), bean.getBiblioteca()
				.getCancionSonando().getStringDuracion());
		actualizaProgreso(tiempo, tiempoToString(tiempo));
	}

	/**
	 * Finaliza la ejecuci&oacute;n de la aplicaci&oacute;n.
	 * 
	 * @param i
	 *            Estado de la finalizaci&oacute;n.
	 */
	public static void salir(int i) {
		System.exit(i);
	}

	/**
	 * Muestra el formulario principal.
	 * 
	 * @see FormPrincipal
	 */
	public static void show() {
		vistaPrincipal.show();
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que establezca como
	 * nueva canci&oacute;n la anterior a la que est&eacute; cargada actualmente
	 * (sonando o no) y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void siguiente() {
		Bean bean = Fachada.siguiente();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al avanzar pista", "XtremeAudio",
					JOptionPane.ERROR_MESSAGE);
		} else {
			actualizaReproduccion(bean);
			Biblioteca b = bean.getBiblioteca();
			int fila = 0;
			int sonando = b.getIndiceListaSonando();
			if (sonando == -1) {
				fila = b.getIndiceCancionActual();
			} else if (sonando == -2) {
				fila = b.getIndiceBusqueda();
			} else {
				fila = b.getPlaylistActual().getIndiceActual();
			}
			vistaPrincipal.actualizaSeleccion(fila + 1);
		}
	}

	/**
	 * Ordena al modelo, a trav&eacute;s de la fachada, que detenga la
	 * reproducci&oacute;n actual y actualiza la vista.
	 * 
	 * @see Dao
	 * @see Fachada
	 * @see FormPrincipal
	 */
	public static void stop() {
		Bean bean = Fachada.stop();
		if (bean == null) {
			JOptionPane.showMessageDialog(null,
					"Se ha producido un error al detener la reproduccion",
					"XtremeAudio", JOptionPane.ERROR_MESSAGE);
		} else {
			if (bean.getEstado().equals("Parado")) {
				actualizaTiempo("00:00", bean.getBiblioteca()
						.getCancionSonando().getStringDuracion());
				actualizaProgreso(0, "00:00");
				actualizaEstado("Parado");
				actualizaTablaLista(bean);
			}
		}
	}

	/**
	 * Formatea el tiempo en segundos como <i>MM:SS</i>.
	 * 
	 * @param segundos
	 *            Los segundos a transformar.
	 * 
	 * @return La cadena formateada.
	 */
	public static String tiempoToString(int segundos) {
		String m, s;
		Integer mins = segundos / 60;
		Integer segs = segundos % 60;
		m = mins.toString();
		s = segs.toString();
		if (mins < 10) {
			m = "0" + m;
		}
		if (segs < 10) {
			s = "0" + s;
		}
		return (m + ":" + s);
	}

	/*--- METODOS PRIVADOS ---*/
	private static void actualizaAleatorio(boolean aleatorio) {
		vistaPrincipal.actualizaAleatorio(aleatorio);
	}

	private static void actualizaArchivo(String ruta, String nombre) {
		vistaPrincipal.actualizaArchivo(ruta, nombre);
	}

	private static void actualizaCaratula(Image image) {
		vistaPrincipal.actualizaCaratula(image);
	}

	private static void actualizaEstado(String estado) {
		vistaPrincipal.actualizaEstado(estado);
	}

	private static void actualizaMute(boolean mute) {
		vistaPrincipal.actualizaMute(mute);
	}

	private static void actualizaPista(String pistaActual, String numPistas) {
		vistaPrincipal.actualizaPista(pistaActual, numPistas);
	}

	private static void actualizaProgreso(int tiempo, String stringTiempo) {
		vistaPrincipal.actualizaProgreso(tiempo, stringTiempo);
	}

	private static void actualizaReproduccion(Bean bean) {
		if (bean.getBiblioteca().getCanciones().size() > 0) {
			setReproducible(true);
			habilitaMenuReproduccion();
			habilitaBotones();
			habilitaProgreso(bean.getBiblioteca().getCancionSonando()
					.getDuracion());

			int tiempo = bean.getTiempoActual();
			actualizaProgreso(tiempo, tiempoToString(tiempo));
			actualizaCaratula(bean.getBiblioteca().getCancionSonando()
					.getCaratula());
			File archivo = bean.getArchivo();
			actualizaArchivo(archivo.toString(), archivo.getName());
			int total;
			if (bean.getBiblioteca().getIndiceListaSonando() == -1) {
				total = bean.getBiblioteca().getCanciones().size();
			} else if (bean.getBiblioteca().getIndiceListaSonando() == -2) {
				total = bean.getBiblioteca().getBusqueda().size();
			} else {
				total = bean.getBiblioteca().getPlaylistSonando()
						.getCanciones().size();
			}
			int pistaActual;
			if (bean.getBiblioteca().getIndiceListaSonando() == -1) {
				pistaActual = bean.getBiblioteca().getIndiceCancionActual() + 1;
			} else if (bean.getBiblioteca().getIndiceListaSonando() == -2) {
				pistaActual = bean.getBiblioteca().getIndiceBusqueda() + 1;
			} else {
				pistaActual = bean.getBiblioteca().getPlaylistSonando()
						.getIndiceActual() + 1;
			}

			actualizaPista(Integer.toString(pistaActual), Integer
					.toString(total));
			actualizaTiempo(tiempoToString(bean.getTiempoActual()), bean
					.getBiblioteca().getCancionSonando().getStringDuracion());
			actualizaEstado(bean.getEstado());
			actualizaTablaInfo(bean);
			actualizaTablaLista(bean);
		}
	}

	private static void actualizaTablaInfo(Bean bean) {
		DefaultTableModel modelo = (DefaultTableModel) vistaPrincipal
				.getTablaInfo().getModel();
		@SuppressWarnings("unchecked")
		Vector<Vector<String>> v = modelo.getDataVector();
		v.elementAt(0).setElementAt(
				bean.getBiblioteca().getCancionSonando().getAutor(), 1);
		v.elementAt(1).setElementAt(
				bean.getBiblioteca().getCancionSonando().getAlbum(), 1);
		v.elementAt(2).setElementAt(
				bean.getBiblioteca().getCancionSonando().getTitulo(), 1);
		v.elementAt(3).setElementAt(
				bean.getBiblioteca().getCancionSonando().getGenero(), 1);
		v.elementAt(4).setElementAt(
				bean.getBiblioteca().getCancionSonando().getAnyo(), 1);
		v.elementAt(5).setElementAt(
				bean.getBiblioteca().getCancionSonando().getPista(), 1);
		v.elementAt(6)
				.setElementAt(
						bean.getBiblioteca().getCancionSonando()
								.getStringDuracion(), 1);
		v.elementAt(7).setElementAt(
				bean.getBiblioteca().getCancionSonando().getFormato(), 1);
		v.elementAt(8).setElementAt(
				bean.getBiblioteca().getCancionSonando().getPath(), 1);
		vistaPrincipal.actualizaTablaInfo(modelo);
	}

	private static void actualizaTiempo(String tiempoActual, String tiempoTotal) {
		vistaPrincipal.actualizaTiempo(tiempoActual, tiempoTotal);
	}

	private static void actualizaVectorLista(DefaultTableModel modelo,
			boolean sonando, int fila, Bean bean, Cancion c, int indiceActual) {
		Vector<Object> v = new Vector<Object>();
		if ((sonando) && (fila == indiceActual)) {
			if (bean.getEstado().equals("Parado")) {
				v.add(new ImageIcon(Controlador.class.getClassLoader()
						.getResource("img/stop_16x16.png")));
			} else if (bean.getEstado().equals("Reproduciendo")) {
				v.add(new ImageIcon(Controlador.class.getClassLoader()
						.getResource("img/play_16x16.png")));
			} else {
				v.add(new ImageIcon(Controlador.class.getClassLoader()
						.getResource("img/pausa_16x16.png")));
			}
		} else {
			v.add(null);
		}
		v.add(Integer.toString(fila + 1));
		v.add(c.getTitulo());
		v.add(c.getAutor());
		v.add(c.getAlbum());
		v.add(c.getStringDuracion());
		modelo.addRow(v);
	}

	private static void creaArbol(Bean bean) {
		DefaultMutableTreeNode raiz = new DefaultMutableTreeNode(new NodoArbol(
				"Biblioteca", -1), true);
		DefaultTreeModel modelo = new DefaultTreeModel(raiz, true);
		if (bean != null) {
			Biblioteca b = bean.getBiblioteca();
			for (int i = 0; i < b.getPlaylists().size(); i++) {
				Playlist p = b.getPlaylist(i);
				raiz.add(new DefaultMutableTreeNode(new NodoArbol(
						p.getNombre(), i), false));
			}
		}
		vistaPrincipal.creaArbol(modelo);
	}

	private static void habilitaBotones() {
		vistaPrincipal.habilitaBotones();
	}

	private static void habilitaMenuReproduccion() {
		vistaPrincipal.habilitaMenuReproduccion();
	}

	private static void habilitaProgreso(int duracion) {
		vistaPrincipal.habilitaProgreso(duracion);
	}

	private static void setReproducible(boolean b) {
		vistaPrincipal.setReproducible(b);
	}

}